/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2002, GeoVISTA Center
 * Licensed under Simplified BSD License
 * This library is developed and distributed for free usage,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * You can redistribute and/or modify it under the terms of the
 * Simplified BSD License
 *
 *
 *
 *
 *
 *
*
* This is a interactive legend
* @Original Author: jin Chen
* @date: Jan 3, 2005$
* @version: 1.0
*/
package edu.psu.geovista.app.visualclassifier.classify.v2.gui;

import edu.psu.geovista.app.visualclassifier.classify.v2.DefaultESVisualClassifier;
import edu.psu.geovista.app.visualclassifier.classify.v2.ESVisualClassifier;
import edu.psu.geovista.app.visualclassifier.classify.v2.LgToolTip;
import edu.psu.geovista.app.visualclassifier.classify.v2.colorpalette.DynamicSwatchPane;
import edu.psu.geovista.app.visualclassifier.classify.v2.colorpalette.v1.DynamicSwatchPaneImpl;
import edu.psu.geovista.app.visualclassifier.classify.v2.colorpalette.v2.FixedSwatchPaneImpl;
import edu.psu.geovista.classification.*;
import edu.psu.geovista.classification.setting.ClassifySetting;
import edu.psu.geovista.common.debug.Debug;
import edu.psu.geovista.ui.event.ClassificationResultEvent;
import edu.psu.geovista.ui.event.ClassificationResultListener;
import edu.psu.geovista.ui.event.DefaultEventSupport;
import epoviz.trex.common.swing.components.jpanel.MouseEventProcessPanel;
import epoviz.trex.common.swing.utils.ImageUtils;
import layout.TableLayout;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.util.*;

public class LegendControl2 extends MouseEventProcessPanel
        implements ClassificationResultListener, LegendControl {
    private static final boolean DEBUG=true;

    private  int defaultWidth = 60;  //default width of the legend control
    private  int defaultHeight = 60;
    private  int expandWidth=100;//expand width
    private  int expandHeight=100;
    private  double labelWeight = 0.2;// 
    //GUI
    DynamicSwatchPane swp;  // 
    protected MyMouseInputAdapter msl;
    protected boolean normalsize= true;//;
    private JLabel xlb=new JLabel();
    private JLabel ylb=new JLabel();
    /*private JPanel xlbp=new JPanel();//x label panel
    private JPanel ylbp=new JPanel();//y label panel*/
    private JButton cornerBtn=new JButton();
    private JPanel labelP=new JPanel();  //display variables' name
    private LgToolTip tooltip=new LgToolTip();
    //classification
    private ESVisualClassifier vc;
    ClassificationResultItf classifyResult;
    HashMap colorCategories=new HashMap(); // 
    public static final String ACTION_SMALL = "small";
    public static final String ACTION_EXPAND = "expand";
    public static final String ACTION_DETAIL = "detail";
    public static final String ACTION_SELECT = "select";
     public static final String ACTION_ADD_SELECT = "addselect";
    public static final String ACTION_DESELECT = "deselect";
    public static final String ACTION_SELECT_ALL = "selectall";
    protected JPopupMenu popupMenu;

    protected Font labelfont = new Font("Arial", Font.BOLD , 11);  //MS Sans Serif
    private Color xbarColor=new Color(185,120,6); ;//new Color(38,97,73):dark green;//0,102,102; 93,54,16 new Color(214,127,21);
    private Color ybarColor=new Color(11, 61, 163);

    DefaultEventSupport eventSupport=new DefaultEventSupport();
    public static final String CLICKED_POINT = "clickedPoint";
    private Map variableDescriptions=new Hashtable();// key, var name; value: var description
    MouseEventProcessPanel mainp;
    //Color[][] colors;
    /**
     *
     * @param colors    
     */
    public LegendControl2(Color[][] colors) {
        this.mainp=new MouseEventProcessPanel();

        int dismissDelay = ToolTipManager.sharedInstance().getDismissDelay();
        ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE );
        setupSwatchPane(colors);
        //2. set up actions
        setupActions();
        // 
        double[][] size={
            {getLabelWeight(),TableLayout.FILL } ,{TableLayout.FILL,getLabelWeight()}
        } ;
        TableLayout ly=new TableLayout(size);
        mainp.setLayout(ly);
        mainp.setOpaque(false);

        this.setLayout(new BorderLayout());
        this.setOpaque(false);
        this.add(mainp);


        setuplabels();
        this.setSize(new Dimension(getExpandWidth(),getExpandHeight()));
        setSmallestMode();
        //setExpandedMode();
       // this.vc=new DefaultESVisualClassifier() ;// 



    }

    private void setupSwatchPane(Color[][] colors) {
        //1. swatchPanes
        swp=new MouseEventPassingSwatchPane(colors);//edu.psu.geovista.app.pcp.toolkits.colorpalette.v1.DynamicSwatchPaneImpl(colors);

        swp.setGap(1,1);
        swp.setSwatchBorderColor(Color.white );
        ((JComponent)swp).setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED) );// .createLineBorder(Color.BLACK ) );
        // 
        // 
        ((JPanel)swp).setToolTipText("");
        msl = new MyMouseInputAdapter() ;
        this.setSwatchPaneMouseListener(swp,msl);
    }
    /**
     *  
     */
    private void setuplabels() {
        JLabel lb=this.getLabel("  lb1");
        ylb=lb;

        AffineTransform rotate=AffineTransform.getRotateInstance(-Math.PI /2);
        Font rotatefont = labelfont.deriveFont(rotate);
        lb.setHorizontalAlignment(SwingConstants.CENTER );// 
        lb.setVerticalAlignment(SwingConstants.BOTTOM );
        lb.setFont(rotatefont);
        lb.setForeground(this.getYbarColor());

        xlb=this.getLabel(" xlb");
        xlb.setForeground(this.getXbarColor());

        JButton btn=new JButton();
        Border lborder = BorderFactory.createLineBorder(new Color(250,250,250,100));
        btn.setBorder(lborder);
        btn.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                setSmallestMode();
            }
        });
        cornerBtn=btn;


    }
    /**
     *  
     */
    private void setSmallestMode(){


        this.mainp.removeAll();
        LegendControl2.this.mainp.revalidate();
        LegendControl2.this.mainp.invalidate();


        int w=(int) (getDefaultWidth()*(1-getLabelWeight()));
        int h=3;
        //setXbarColor(Color.green);
        JPanel xlbp = this.getBarPanel(getXbarColor(), new Dimension(w,h));

        w=3;
        h=(int) (getDefaultWidth()*(1-getLabelWeight()));
        //setYbarColor(Color.blue);
        JPanel ylbp = this.getBarPanel(getYbarColor(), new Dimension(w,h));

        JPanel cornerp=new JPanel();
        cornerp.setOpaque(false);


        this.mainp.add  (ylbp,"0,0,F,F");
        this.mainp.add  (xlbp,"1,1,F,F");    //this.add  (lb2,"1,1,C,C");
        this.mainp.add  (cornerp,"0,1,F,F");
        final JComponent swatchp = (JComponent)swp;
        this.mainp.add  (swatchp,"1,0,F,F");
        //this.remove
         this.setSize(new Dimension(getDefaultWidth(),getDefaultHeight()));
        LegendControl2.this.mainp.validate();    // 
        LegendControl2.this.validate();    // 


        Runnable repaint = new Runnable(){
                    public void run() {
                        LegendControl2.this.repaint();
                       //System.out.println("setSmallestMode() call LegendControl2.this.repaint();");
                    }
                };
        SwingUtilities.invokeLater(repaint);


    }

    private void setExpandedMode(){
         this.mainp.removeAll();
         this.setSize(new Dimension(getExpandWidth(),getExpandHeight()));
        LegendControl2.this.mainp.revalidate();



        String fullpath= DefaultESVisualClassifier.IMAGES+"small_legend_arrow.gif";////DfPcp.IMAGES+"small_legend_arrow.gif";//"Reset.gif";//
        final ImageIcon arrowIcon = ImageUtils.getImageIconByFullName(fullpath);
        cornerBtn.setIcon(arrowIcon);
        cornerBtn.setBorder(BorderFactory.createEmptyBorder());
        cornerBtn.setRolloverEnabled(false); //rollover --> yellow color, not beautiful
        this.mainp.add (ylb,"0,0,F,F"); // 
        this.mainp.add  (xlb,"1,1,F,F");    //this.add  (lb2,"1,1,C,C");
        this.mainp.add  (cornerBtn,"0,1,F,F");
        final JComponent swtachp = (JComponent)swp;
        this.mainp.add  (swtachp,"1,0,F,F");
        LegendControl2.this.mainp.validate();
        LegendControl2.this.validate();

        Runnable repaint = new Runnable() {
            public void run() {

                //LegendControl2.this.revalidate();
                //swtachp.repaint();// 
                LegendControl2.this.repaint();
            }
        };
         SwingUtilities.invokeLater(repaint);

    }


    private JLabel getLabel(String n){
        JLabel l=new JLabel();
        l.setText(n);
        Font font=this.labelfont ;
        l.setFont(font);
        l.setBackground(new Color(250,250,250,80));
        //l.setBorder(BorderFactory.createLineBorder(Color.BLACK ) );
        l.setOpaque(true);
        //l.setPreferredSize(new Dimension(100,100));
       return l;

    }
    /**
     *  
     * @param c          color of the bar
     * @param barsize    size of the bar
     * @return
     */
    public static JPanel getBarPanel(Color c,Dimension barsize ){
        JLabel l=new JLabel();
        l.setBackground(c);
        l.setPreferredSize(barsize);   //   new Dimension(50,5)
        l.setOpaque(true);
        JPanel p=new JPanel();
        p.setAlignmentX(SwingConstants.CENTER);
        p.setAlignmentY(SwingConstants.CENTER);
        p.setOpaque(false);
        p.add(l);
        return p;

    }
    private void setupActions(){
        Action small=new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                System.out.println(ACTION_SMALL);
                setSmallestMode();
            }
        };
        small.putValue(Action.NAME ,"Smallest");
        //small.putValue(Action.);
        Action expand=new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                System.out.println(ACTION_EXPAND);
                setExpandedMode();
            }
        };
        expand.putValue(Action.NAME,"Expanded");

        Action detail=new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                //System.out.println(ACTION_DETAIL);
                ESVisualClassifier vc = getVisualClassifier();
                if(vc !=null)
                vc.showup();

                else
                    System.out.println(ACTION_DETAIL);
            }
        };
        detail.putValue(Action.NAME,"Detailed");

        Action select=new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                Object v = this.getValue(CLICKED_POINT);
                if(v!=null&&v instanceof Point){
                    Point clp=(Point) v;//clicking point with  location values in compoent's coordination
                    select(clp.x, clp.y);

                }
            }
        };

        // 
        select.putValue(Action.NAME,"Select the category");

        Action addselect=new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                Object v = this.getValue(CLICKED_POINT);
                if(v!=null&&v instanceof Point){
                    Point clp=(Point) v;//clicking point with  location values in compoent's coordination
                    addselect(clp.x, clp.y);

                }
            }
        };
        addselect.putValue(Action.NAME,"Add the category to the selection");

        Action deselect=new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                Object v = this.getValue(CLICKED_POINT);
                if(v!=null&&v instanceof Point){
                    Point clp=(Point) v;//clicking point with  location values in compoent's coordination
                    deselect(clp.x, clp.y);

                }
            }
        };
        deselect.putValue(Action.NAME,"Deselect the category");

         Action selectall=new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                                   selectAll();
            }
        };
        selectall.putValue(Action.NAME,"Select all");
        // 

        ActionMap actionMap = this.getActionMap();
        actionMap.put(ACTION_SMALL,small);
        actionMap.put(ACTION_EXPAND,expand);
        actionMap.put(ACTION_DETAIL,detail);

        // 
        actionMap.put(ACTION_SELECT,select);
        actionMap.put(ACTION_ADD_SELECT,addselect);
        actionMap.put(ACTION_DESELECT,deselect);
        actionMap.put(ACTION_SELECT_ALL,selectall);


    }

    public JPopupMenu getPopupMenu() {
        return popupMenu;
    }

    /*******************************************************************************************************
     *                services
     *******************************************************************************************************/
    /**
     * select the cluster in the point
     * @param x
     * @param y
     */
    public void select(int x, int y){
        DynamicSwatchPaneImpl swatchp = ((DynamicSwatchPaneImpl)swp);
        DynamicSwatchPaneImpl.Swatch swatch = swatchp.getSwatchByLocation(x ,y);
        swp.selectSwatch(swatch);

        CategoryItf ctg = this.getCategory(swatch);
         if(ctg==null){
            Debug.debug(DEBUG,"not found category for point ["+x+","+y+"]");
        }

        if (ctg!=null){
            int[] ids = DefaultESVisualClassifier.getMemberIds(new CategoryItf[]{ctg});
            this.eventSupport.fireSelectionChanged(ids);
        }
        this.repaint();
    }

    /**
     *
     * add the cluster located at (x,y)
     * @param x
     * @param y
     */
    public void addselect(int x, int y){
        DynamicSwatchPaneImpl swatchp = ((DynamicSwatchPaneImpl)swp);
        DynamicSwatchPaneImpl.Swatch swatch = swatchp.getSwatchByLocation(x ,y);
        swp.tryAddSelection(swatch);
        Set<DynamicSwatchPaneImpl.Swatch> selectedSwatches = swp.getSelectedSwatches();
        this.repaint();
        fireSelectionEvent(selectedSwatches);
    }



    /**
     * remove the cluster located at (x,y)
     * @param x
     * @param y
     */
    public void deselect(int x,int y){
       DynamicSwatchPaneImpl swatchp = ((DynamicSwatchPaneImpl)swp);
       DynamicSwatchPaneImpl.Swatch swatch = swatchp.getSwatchByLocation(x ,y);
       swp.deselectSwatch(swatch);
        this.repaint();
       Set<DynamicSwatchPaneImpl.Swatch> selectedSwatches = swp.getSelectedSwatches();
       fireSelectionEvent(selectedSwatches);
    }
    public void selectAll(){
        swp.clearSelection();//= select all from GUI point of view
       // CategoryItf[] ctgs = vc.getCategories();
        //CategoryItf[] ctgs = classifyResult.getCategories();

        // int[] ids = DefaultESVisualClassifier.getMemberIds(ctgs);
        this.eventSupport.fireSelectionChanged(new int[]{}); //an empty array mean select all

    }

    private CategoryItf getCategory( DynamicSwatchPaneImpl.Swatch swatch){
        CategoryItf ctg=null;

         if (swatch!=null){
             Color color = swatch.getColor();
             Object obj = this.colorCategories.get(color);
             ctg = (CategoryItf) obj;
         }

        return ctg;
    }
    private void fireSelectionEvent(Set<DynamicSwatchPaneImpl.Swatch> selectedSwatches) {
        int size = selectedSwatches.size();
        if(size >0){
        int i=0;
        CategoryItf[] ctgs=new CategoryItf[size];
        for (Iterator iterator = selectedSwatches.iterator(); iterator.hasNext();) {
            DynamicSwatchPaneImpl.Swatch swt = (DynamicSwatchPaneImpl.Swatch) iterator.next();
            CategoryItf category = this.getCategory(swt);
            ctgs[i++]=category;
        }
            int[] ids = DefaultESVisualClassifier.getMemberIds(ctgs);
            this.eventSupport.fireSelectionChanged(ids);

        }
    }

    public void doClassification(final ClassifySetting settings){
        final ESVisualClassifier vc = getVisualClassifier();
        /**
         *  
         *  
         *  
         *  
         *  
         *  
         *  
         *  
         */
        ((DefaultESVisualClassifier) vc).classifyOnLegendControl(settings);

       /* if(vc !=null)  {
                //todo temp
                // vc.doClassification(settings);
             SwingUtilities.invokeLater(new Runnable() { //  
                  public void run() {

                      ((DefaultESVisualClassifier) vc).classifyOnLegendControl(settings);//classifyOnVariableChanged();//classifyUpdateGUI(settings);
                  }
              } );

            }*/
    }

    public void setColors(Color[] colors){
        this.swp.setColors(colors);
        //this.setSwatchPaneMouseListener(swp,msl); //since swatches are newly created, need attach mouselistener again
    }
    public void setColors(Color[][] colors){
        this.swp.setColors(colors);
        //this.setSwatchPaneMouseListener(swp,msl); //since swatches are newly created, need attach mouselistener again
    }


    public void setXvarname(String s) {
        String desc = this.getVariableDescription(s.trim());
        if(s!=null&&!s.trim().equals("") )
            s=" "+s;
        setLabel(this.xlb ,s);


            xlb.setToolTipText(desc);

    }

    public void setYvarname(String s) {
       String desc = this.getVariableDescription(s.trim());
        if(s!=null&&!s.trim().equals("") )
            s=" "+s;

        setLabel(this.ylb ,s);

            ylb.setToolTipText(desc);

    }

    private void setLabel(JLabel lb, String s){
        if(s==null||s.trim().equals("") ){
            lb.setText("");
        }
        else{
            lb.setText(s);
        }
        //lb.setFont(new Font("Arial", 1, 14));

    }

    public void setVisualClassifier(ESVisualClassifier vc) {
        this.vc=vc;
    }

     public ESVisualClassifier getVisualClassifier() {
        if(vc==null){
            vc=new DefaultESVisualClassifier();// 
        }
        return vc;
    }
   /* public ESVisualClassifier getVisualClassifier() {
        return vc;
    }*/

    /*******************************************************************************************************
     *                event
     *******************************************************************************************************/
    private void setSwatchPaneMouseListener(DynamicSwatchPane swp,MouseInputAdapter msl){
        JPanel p=(JPanel) swp;
        p.removeMouseListener(msl); //prevent duplication
        p.addMouseListener(msl);

        p.removeMouseMotionListener((MouseMotionListener)msl); //prevent duplication
        p.addMouseMotionListener((MouseMotionListener)msl);

    }

    public void classificationResultChanged(ClassificationResultEvent e) {
        ClassificationResultItf cr = (ClassificationResultItf) e.getClassificationResult();
        if(cr==null)return;
        mapColorsCategories(cr);

        this.repaint();

    }




    /*******************************************************************************************************
     *                Function
     *******************************************************************************************************/

    /***********************************************************************************
     *         Color and classification map
     ************************************************************************************/
    /**
     * Legend has classification and swatch has only color
     * Assume each category has a unique color, we can
     * set up a map between color and category
     * @param cr
     */
    private void mapColorsCategories(ClassificationResultItf cr) {
        if (cr==null)return;
        int colcount = cr.getNumberOfClassX(); //num of category in x direction , it is actually # of column in a legend
        int rowcount = cr.getNumberOfClassY();//num of category in y direction , it is actually # of row in a legend
        this.colorCategories.clear();

        if(colcount>0&&rowcount>0){//2 dimension
            Color[][] colors=new Color[rowcount][colcount];

            for (int i=rowcount-1;i>=0;i--){
                for (int j=0;j<colcount;j++){
                    Category2D ctg = cr.getCategory(j,i);
                    if(ctg!=null&&ctg.getVisualInfo()!=null){
                        VisualInfo vf = ctg.getVisualInfo();
                           Color color = vf.getColor();
                           colors[i][j]=color;
                               this.colorCategories.put(color, ctg);
                    }
                    else{
                        //todo null category or color exception
                    }
                }
            }//for
            this.swp.setColors(colors);
           // this is for enlarged LegendControl, for now, we not use  enlarged LegendControl
            String attX = cr.getAttX();
            String attY = cr.getAttY();
            this.setXvarname(attX);
            this.setYvarname(attY);

        }//if
        else if(colcount>0){//1 dimension
            Color[] colors=new Color[colcount];
            for (int i=0;i<colcount;i++){

                CategoryItf category = cr.getCategory(i);
                if(category!=null&&category.getVisualInfo()!=null){
                    Color color = category.getVisualInfo().getColor();
                    colors[i]=color;
                    this.colorCategories.put(color, category);
                }
            }//for
          /*  Color[][] tempc=new Color[colors.length ][1];
            for (int i=0;i<tempc.length ;i++){
                 tempc[i]=new Color[]{colors[i]};

            }*/
          //  this.swp.setColors(tempc);
          this.swp.setColors(colors);
           String attX = cr.getAttX();
            this.setXvarname(attX);
            this.setYvarname("");
        }//else
    }


    /*******************************************************************************************************
     *                support
     *******************************************************************************************************/
    //todo add selection event
    private void precessMouseClick ( MouseEvent e){
        int id = e.getID();
        if(id==MouseEvent.MOUSE_CLICKED){
            int button = e.getButton();
            if(button==1){ //normal left click
                int clickCount = e.getClickCount();
                ESVisualClassifier vc = getVisualClassifier();
                if(clickCount==2){
                    //System.out.println("double clicked");
                    if(vc !=null)
                        vc.showup();
                    //System.out.println("click 2");
                    //resetSize();
                }
                else  if(clickCount==1){
                    if(vc !=null){
                        //vc.showup();
                    }
                    //resetSize();
                    //System.out.println("click 1");
                }
            }
            else if (button==3){//right click
                int x = e.getX();
                int y = e.getY();

                JComponent invoker = (JComponent)LegendControl2.this;
                ActionMap am = this.getActionMap();
                Action small = am.get(ACTION_SMALL);
                Action expand = am.get(ACTION_EXPAND);
                Action detail = am.get(ACTION_DETAIL);
                Action select = am.get(ACTION_SELECT);
                Action addselect = am.get(ACTION_ADD_SELECT);
                  Action deselect = am.get(ACTION_DESELECT);
                 Action selectall = am.get(ACTION_SELECT_ALL);
                Point clicked=new Point(x,y);

                 if(select!=null)select.putValue(CLICKED_POINT,clicked); //keep where u click
                 if(addselect!=null)addselect.putValue(CLICKED_POINT,clicked); //keep where u click
                 if(deselect!=null)deselect.putValue(CLICKED_POINT,clicked); //keep where u click
                 if(selectall!=null)selectall.putValue(CLICKED_POINT,clicked); //keep where u click


                JPopupMenu popupMenu = new JPopupMenu();

                JMenuItem smallm=new JMenuItem(small);
                JMenuItem expandm=new JMenuItem(expand);
                JMenuItem detailm=new JMenuItem(detail);

                if(select!=null){
                    JMenuItem selectm=new JMenuItem(select);

                    JMenuItem addselectm=new JMenuItem(addselect);

                    JMenuItem deselectm=new JMenuItem(deselect);
    
                    JMenuItem selectallm=new JMenuItem(selectall);


                    JMenu selectmn=new JMenu("Select...");
                    selectmn.add(selectm);
                    selectmn.add(addselectm);
                    selectmn.add(deselectm);
                    selectmn.add(selectallm);
                     popupMenu.add(selectmn);

                    popupMenu.addSeparator();
                }
                popupMenu.add(smallm);
                popupMenu.add(expandm);
                popupMenu.add(detailm);




                popupMenu.show(invoker,x ,y);
            }

        }
    }
    private void processMouseMoveOn(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        DynamicSwatchPaneImpl swatchp = ((DynamicSwatchPaneImpl)swp);
        DynamicSwatchPaneImpl.Swatch swatch = swatchp.getSwatchByLocation(x ,y);
        if (swatch!=null){
            Color color = swatch.getColor();
            Object obj = this.colorCategories.get(color);
            CategoryItf ctg = (CategoryItf) obj;
            if(ctg!=null){
                //String tooltip = this.getTooltip(ctg);
                Point colorIndex = swatch.getIndex();
                Color[] rowColors = swatchp.getRowColors(colorIndex.x );
                Color[] columnColors = swatchp.getColumnColors(colorIndex.y );
                this.tooltip.setTooltip(rowColors,columnColors,ctg);
                tooltip.repaint();
               // ((JPanel)swp).setToolTipText(tooltip);
            }

        }
    }

    private String getTooltip(CategoryItf ctg){
        String s="";
        String xs="X variable:";

        if(ctg instanceof Category2D){//2D category
            String ys="Y variable:";
            Category2D ctg2d = ((Category2D)ctg);

            Range xr = ctg2d.getXRange();
            Range yr = ctg2d.getYRange();
            xs=xs+xr.toString()+"\n" ;
            ys=ys+yr.toString() +"\n" ;
            s=xs+ys;
        }
        else{//1 dimension category
            Range xr = ctg.getRange();
            xs=xs+xr.toString()+"\n" ;
            s=xs;
        }
        return s;

    }
    private void resetSize(){
        if(normalsize){
            this.setSize(new Dimension(getExpandWidth(),getExpandHeight()));
            this.add(this.labelP ,BorderLayout.SOUTH);
            normalsize=false;//true;
        }
        else{
            this.setSize(new Dimension(getDefaultWidth(),getDefaultHeight()));
            this.remove(labelP);
            normalsize=true;//true;
        }
        this.revalidate();
        this.repaint();
        JComponent parent = (JComponent) this.getParent();
        Component[] cps = parent.getComponents();
        parent.revalidate();
        parent.repaint();
    }



    /*******************************************************************************************************
     *                properties
     *******************************************************************************************************/
public String  getVariableDescription(String varname) {
        if( variableDescriptions==null)return "";

        Object o = variableDescriptions.get(varname);
        if(o==null) return "";
        else return (String) o ;
    }

    public void setVariableDescriptions(Map variableDescriptions) {
        this.variableDescriptions = variableDescriptions;
    }
    public Color getXbarColor() {
        return xbarColor;
    }

    public void setXbarColor(Color xbarColor) {
        this.xbarColor = xbarColor;
    }

    public Color getYbarColor() {
        return ybarColor;
    }

    public void setYbarColor(Color ybarColor) {
        this.ybarColor = ybarColor;
    }

    public int getDefaultWidth() {
        return defaultWidth;
    }

    public void setDefaultWidth(int defaultWidth) {
        this.defaultWidth = defaultWidth;
    }

    public int getDefaultHeight() {
        return defaultHeight;
    }

    public void setDefaultHeight(int defaultHeight) {
        this.defaultHeight = defaultHeight;
    }

    public int getExpandWidth() {
        return expandWidth;
    }

    public void setExpandWidth(int expandWidth) {
        this.expandWidth = expandWidth;
    }

    public int getExpandHeight() {
        return expandHeight;
    }

    public void setExpandHeight(int expandHeight) {
        this.expandHeight = expandHeight;
    }

    public double getLabelWeight() {
        return labelWeight;
    }

    public void setLabelWeight(double labelWeight) {
        this.labelWeight = labelWeight;
    }

    public DefaultEventSupport getEventSupport() {
        return eventSupport;
    }

    public JComponent getMouseEventSourceComponent() {
        return mainp;  //To change body of implemented methods use File | Settings | File Templates.
    }



    class MyMouseInputAdapter extends MouseInputAdapter {

        public void mouseClicked(MouseEvent e){
            precessMouseClick(e);
        }
        public void mouseMoved(MouseEvent e) {
            processMouseMoveOn(e);
        }
        public void mouseDragged(MouseEvent e) {}

    }
    /************************************************************************************
     *               
     ************************************************************************************/
    class MouseEventPassingSwatchPane extends DynamicSwatchPaneImpl{
        public MouseEventPassingSwatchPane(Color[][] colors) {
            super(colors);
            this.enableEvents(AWTEvent.MOUSE_EVENT_MASK );
            this.enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
        }

        protected void processMouseEvent(MouseEvent e) {
            super.processMouseEvent(e );
            MouseEventProcessPanel p=(MouseEventProcessPanel) LegendControl2.this.mainp ;
            p.processMouseEvent(e);
        }
        protected void processMouseMotionEvent(MouseEvent e) {
            super.processMouseMotionEvent(e);
            MouseEventProcessPanel p=(MouseEventProcessPanel) LegendControl2.this.mainp ;
            p.processMouseMotionEvent(e);
            //System.out.println("processMouseMotionEvent");
        }
      /**
       *  
       * @return
       */
         public JToolTip createToolTip() {
            tooltip.setComponent(this);
            System.out.println("create customized tooltip");
            return tooltip;
        }
    }

    public  static Color[][] getSampleColors(){
        int[][] colorValues=new int[][]{
            {255, 255, 255, // first row.
             192, 192, 192,
             255, 0, 0,
             255, 255, 0,
             0, 255, 0,
             0, 255, 255,
             0, 0, 255,
             255, 0, 255},
            {0, 0, 0,  // second row.
             128, 128, 128,
             128, 0, 0,
             128, 128, 0,
             0, 128, 0,
             0, 128, 128,
             0, 0, 128,
             128, 0, 128,},
            {255, 199, 199,  // 3rd row.
             83, 109, 165,
             204,  255,204,
             153, 153, 204,
             204, 204, 214,
             0, 180, 110,
             252, 253, 205,
             212, 133, 213}
        };
        Color[][] mycolors= FixedSwatchPaneImpl.convert2RowBased(colorValues);
        //SwatchPanel sp=new SwatchPanel(30,30,colorValues);
        return mycolors;
    }

}

